/* 
 * File:   CommandMap.cpp
 * Author: Gab'z
 * 
 * Created on 27 mai 2012, 18:22
 */

#include "CommandMap.h"
#include "UndoCommand.h"
#include "RedoCommand.h"
#include "operator/Eval.h"
#include "operator/Swap.h"
#include "operator/nullary/Clear.h"
#include "operator/nullary/Drop.h"
#include "operator/unary/Cos.h"
#include "operator/unary/Cosh.h"
#include "operator/unary/Cube.h"
#include "operator/unary/Dup.h"
#include "operator/unary/Fact.h"
#include "operator/unary/IntegerConverter.h"
#include "operator/unary/Inv.h"
#include "operator/unary/Ln.h"
#include "operator/unary/Log.h"
#include "operator/unary/RationnalConverter.h"
#include "operator/unary/RealConverter.h"
#include "operator/unary/Sign.h"
#include "operator/unary/Sin.h"
#include "operator/unary/Sinh.h"
#include "operator/unary/Sqr.h"
#include "operator/unary/Sqrt.h"
#include "operator/unary/Tan.h"
#include "operator/unary/Tanh.h"
#include "operator/binary/Add.h"
#include "operator/binary/Sub.h"
#include "operator/binary/Mul.h"
#include "operator/binary/Div.h"
#include "operator/binary/Mod.h"
#include "operator/binary/Pow.h"
#include "operator/unary/ComplexConverter.h"
#include "operator/nary/Sum.h"
#include "operator/nary/Mean.h"
#include "parameters/IntegerParameterCommand.h"
#include "parameters/RationnalParameterCommand.h"
#include "parameters/RealParameterCommand.h"
#include "parameters/ComplexParameterCommand.h"
#include "parameters/DegreeParameterCommand.h"
#include "parameters/RadianParameterCommand.h"
#include "parameters/KeyboardParameterCommand.h"
#include "parameters/InstantComputeParameterCommand.h"
#include "parameters/IntegerDivisionParameterCommand.h"
#include "parameters/VisibleStackSizeParameterCommand.h"
#include "stacklist/NewStackCommand.h"
#include "stacklist/DuplicateStackCommand.h"
#include "stacklist/RemoveStackCommand.h"
#include "stacklist/SwitchCurrentStackCommand.h"

namespace calculator {

    CommandMap* CommandMap::instance = 0;

    CommandMap::CommandMap() {
        // on ajoute ici un par un les instances des operateurs fixes à la map
        addCommand(new Eval("EVAL"));

        addCommand(new UndoCommand("UNDO"));
        addCommand(new RedoCommand("REDO"));

        addCommand(new Clear("CLEAR"));
        addCommand(new Drop("DROP"));
        addCommand(new Dup("DUP"));

        addCommand(new Add("+"));
        addCommand(new Sub("-"));
        addCommand(new Mul("*"));
        addCommand(new Div("/"));
        addCommand(new Pow("POW"));
        addCommand(new Mod("MOD"));

        addCommand(new IntegerConverter("TOINT"));
        //addCommand(new RationnalConverter("TORAT"));
        addCommand(new RealConverter("TOREAL"));
        addCommand(new ComplexConverter("TOCOMP"));

        addCommand(new Cos("COS"));
        addCommand(new Cosh("COSH"));
        addCommand(new Sin("SIN"));
        addCommand(new Sinh("SINH"));
        addCommand(new Tan("TAN"));
        addCommand(new Tanh("TANH"));

        addCommand(new Sign("SIGN"));
        addCommand(new Inv("INV"));
        addCommand(new Sqr("SQR"));
        addCommand(new Cube("CUBE"));
        addCommand(new Sqrt("SQRT"));
        addCommand(new Fact("FACT"));

        addCommand(new Ln("LN"));
        addCommand(new Log("LOG"));

        addCommand(new IntegerParameterCommand("INT"));
        addCommand(new RationnalParameterCommand("RAT"));
        addCommand(new RealParameterCommand("REAL"));
        addCommand(new ComplexParameterCommand("COMPLEX"));

        addCommand(new DegreeParameterCommand("DEG"));
        addCommand(new RadianParameterCommand("RAD"));

        addCommand(new KeyboardParameterCommand("KEYBOARD"));
        addCommand(new InstantComputeParametersCommand("INSTANT"));
        addCommand(new IntegerDivisionParameterCommand("IDIV"));
        addCommand(new VisibleStackSizeParameterCommand("SIZE"));

        addCommand(new NewStackCommand("SNEW"));
        addCommand(new DuplicateStackCommand("SDUP"));
        addCommand(new RemoveStackCommand("SREM"));
        addCommand(new SwitchCurrentStackCommand("SWITCH"));

        addCommand(new Swap("SWAP"));

        addCommand(new Sum("SUM"));
        addCommand(new Mean("MEAN"));
    }

    CommandMap* CommandMap::getInstance() {
        if (instance == 0) {
            instance = new CommandMap();
        }
        return instance;
    }

    void CommandMap::deleteInstance() {
        if (instance != 0) delete instance;
    }

    CommandMap::~CommandMap() {
        for (std::map<const std::string, const Command*>::iterator it = _commandMap.begin();
                it != _commandMap.end();
                it++) {
            delete it->second;
        }
        _commandMap.clear();
        //
        //        for (std::map<const std::string, const UserCommand*>::iterator it = _userCommandMap.begin();
        //                it != _userCommandMap.end();
        //                it++) {
        //            delete it->second;
        //        }
        //        _userCommandMap.clear();
    }

    // concerne uniquement les commandes utilisateur
    //
    //    void CommandMap::addReplaceUserCommand(const UserCommand* uc) {
    //        std::map<const std::string, const UserCommand*>::iterator it = _userCommandMap.find(uc->toString());
    //        if (it != _userCommandMap.end()) {
    //            delete it->second;
    //            _userCommandMap.erase(it);
    //        }
    //        std::pair<const std::string, const UserCommand*> paire(uc->toString(), uc);
    //        _userCommandMap.insert(paire);
    //    }
    //
    //    // ne doit etre utilisé que lors des actions undo/redo
    //
    //    void CommandMap::removeUserCommand(const std::string& str) {
    //        std::map<const std::string, const UserCommand*>::iterator it = _userCommandMap.find(str);
    //
    //        if (it != _userCommandMap.end()) {
    //            delete it->second;
    //            _userCommandMap.erase(it);
    //        } else {
    //            throw CommandException("Erreur de suppression de l'opérateur. Cet opérateur n'existe pas : " + str);
    //        }
    //    }

    bool CommandMap::isCommandName(const std::string& str) const {
        //return (_commandMap.find(str) != _commandMap.end() || _userCommandMap.find(str) != _userCommandMap.end());
        return (_commandMap.find(str) != _commandMap.end());
    }

    const Command* CommandMap::getCommand(const std::string& str) const throw (CommandException) {
        std::map<const std::string, const Command*>::const_iterator it = _commandMap.find(str);
        if (it == _commandMap.end()) {
            std::string error = "Cet opérateur n'existe pas : ";
            throw CommandException(error + str);
        } else return it->second->clone();
        // TODO inclure userCommand
    }

    void CommandMap::addCommand(const Command* command) {
        std::pair<const std::string, const Command*> paire(command->toString(), command);
        _commandMap.insert(paire);
    }
}
